package uy.com.tsi2G7.superbet.bet;

import java.math.BigDecimal;
import java.rmi.RemoteException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import javax.ejb.EJB;
import javax.ejb.Stateless;
import javax.faces.bean.ManagedBean;

import uy.com.tsi2G7.superbet.account.AccountService;
import uy.com.tsi2G7.superbet.account.InsufficientFoundException;
import uy.com.tsi2G7.superbet.account.dao.AccountNotFoundException;
import uy.com.tsi2G7.superbet.bet.dao.BetStore;
import uy.com.tsi2G7.superbet.event.EventMarket;
import uy.com.tsi2G7.superbet.event.EventMarketResult;
import uy.com.tsi2G7.superbet.event.EventService;
import uy.com.tsi2G7.superbet.ui.BetHistoryDescriptor;
import uy.com.tsi2G7.superbet.user.UserNotificationException;
import uy.com.tsi2G7.superbet.user.UserNotifications;
import uy.com.tsi2G7.superbet.util.SpringContext;

@ManagedBean(name = "betService")
@Stateless
public class BetServiceImpl implements BetService {

	private BetStore betStore;
	@EJB
	private AccountService accountService;
	@EJB
	private EventService eventtService;
	@EJB
	private UserNotifications userNotifications;

	@Override
	public void doSimpleBet(String userId, long eventTypeId, long eventId,
			long marketId, long marketResultId, BigDecimal amount)
			throws RemoteException, AccountNotFoundException,
			InsufficientFoundException {
		SimpleBet simpleBet = new SimpleBet();
		simpleBet.setAmount(amount);
		simpleBet.setDate(new Date());
		simpleBet.setEventId(eventId);
		simpleBet.setMarketId(marketId);
		simpleBet.setUserId(userId);
		simpleBet.setEventTypeId(eventTypeId);
		simpleBet.setResultId(marketResultId);
		doBet(simpleBet);
	}
	
	@Override
	public void doUserBet(String userId, long eventTypeId, long eventId,long marketId, long marketResultId, BigDecimal amount, boolean result)
	throws RemoteException, AccountNotFoundException,InsufficientFoundException {
		SimpleBet simpleBet = new SimpleBet();
		simpleBet.setAmount(amount);
		simpleBet.setDate(new Date());
		simpleBet.setEventId(eventId);
		simpleBet.setMarketId(marketId);
		simpleBet.setUserId(userId);
		simpleBet.setEventTypeId(eventTypeId);
		simpleBet.setResultId(marketResultId);
		if (result){
			simpleBet.setState(BetState.PENDING);
		}
		simpleBet.setResult(result);
		simpleBet.setUserBet(true);
		doBet(simpleBet);
	}
	
	@Override
	public Bet confirmUserBet(String userId, long marketId, long marketResultId)throws RemoteException, AccountNotFoundException, InsufficientFoundException {
		Bet bet = getBetStore().getUserBet(userId,marketId,marketResultId);
		bet.setState(BetState.OPEN);
		doBet(bet);
		return bet;
	}

	public BetStore getBetStore() {
		if (betStore == null)
			betStore = (BetStore) SpringContext.getApplicationContext()
					.getBean("betStore");
		return betStore;
	}

	public void setBetStore(BetStore betStore) {
		this.betStore = betStore;
	}

	@Override
	public List<BetHistoryDescriptor> getlastUserSimpleBetsDescription(
			String userId) {
		return getBetStore().getlastUserSimpleBetsDescription(userId);
	}

	@Override
	public void fireEventFinished(long eventTypeId, long marketId)
			throws RemoteException, AccountNotFoundException,
			UserNotificationException {
		// TODO hacerlo transaccional
		List<SimpleBet> bets = getBetStore().getOpenBetsByMarketId(eventTypeId,
				marketId);
		List<EventMarketResult> results = eventtService.getMarketResults(
				eventTypeId, marketId);
		for (SimpleBet bet : bets) {
			for (EventMarketResult eventMarketResult : results) {
				System.out.println(eventMarketResult.getId());
				System.out.println(bet.getResultId());
				if (eventMarketResult.getId() == bet.getResultId()) {

					if(bet.getState()==BetState.PENDING){
						userNotifications.sendBetVoid(
								eventtService.getMarketById(
										eventMarketResult.getMarketId())
										.getName(),
								eventMarketResult.getName(),
								BigDecimal.ZERO, bet.getUserId());
					}else if (bet.isComposite()) {
						CompositeBet compositeBet = getBetStore()
								.getOpenCompositeBetBySon(bet.getId());
						if (compositeBet.getState() == BetState.OPEN) {
							List<Long> ids = new ArrayList<Long>();
							for (SimpleBet simpleBet : compositeBet.getBets()) {
								ids.add(simpleBet.getResultId());
							}
							List<EventMarketResult> res = eventtService
									.getMarketResultsById(ids);
							boolean success = true;
							boolean finished = true;
							for (EventMarketResult marketResult : res) {
								if (marketResult.getWinAmount().doubleValue() < 0)
									finished = false;
								else if (marketResult.getWinAmount()
										.doubleValue() == 0)
									success = false;
							}
							if (finished) {
								getBetStore().closeBet(compositeBet.getId());
								BigDecimal amount = BigDecimal.ONE;
								String betDescription = "";
								String userId = compositeBet.getUserId();
								String eventDescription = "";
								for (EventMarketResult marketResult : res) {
									if (success)
										amount = amount.multiply(marketResult
												.getWinAmount());
									eventDescription = eventDescription
											+ eventtService.getMarketById(
													marketResult.getMarketId())
													.getName() + "\n";
									betDescription = betDescription
											+ marketResult.getName() + "\n";
								}
								if (success){
									amount = amount.multiply(compositeBet
											.getAmount());
									accountService.creditBet(amount,bet.getUserId());
								}
								else
									amount = BigDecimal.ZERO;
								userNotifications.sendBetResult(
										eventDescription, betDescription,
										amount, userId);
							}
						}
					} else {
						
						BigDecimal amount = BigDecimal.ZERO;
						if(bet.isUserBet()){
							if((eventMarketResult.getWinAmount().compareTo(
									BigDecimal.ZERO) > 0&&bet.isResult())||
									eventMarketResult.getWinAmount().compareTo(
											BigDecimal.ZERO) <= 0&&!bet.isResult())
								amount=bet.getAmount().multiply(BigDecimal.valueOf(2));
						}else if (eventMarketResult.getWinAmount().compareTo(
								BigDecimal.ZERO) > 0)
							amount=bet.getAmount().multiply(
									eventMarketResult.getWinAmount());
						
						if(amount.doubleValue()>0)
							accountService.creditBet(
									amount,bet.getUserId());
						
						userNotifications.sendBetResult(
								eventtService.getMarketById(
										eventMarketResult.getMarketId())
										.getName(),
								eventMarketResult.getName(),
								amount, bet.getUserId());
					}
					
					getBetStore().closeBet(bet.getId());
				}
			}
		}
	}

	@Override
	public void doBet(Bet bet) throws RemoteException,AccountNotFoundException, InsufficientFoundException {
		if (!bet.getState().equals(BetState.PENDING)){
			accountService.debitBet(bet.getAmount(), bet.getUserId());
		}
		getBetStore().storeBet(bet);
	}

	@Override
	public void updateResultAndBets(long marketId, long resultId)
			throws RemoteException, AccountNotFoundException,
			UserNotificationException {
		EventMarket market = eventtService.getMarketById(marketId);
		eventtService.setWinner(market, resultId);
		fireEventFinished(market.getEventTypeId(), marketId);

	}

	public void setAccountService(AccountService accountService) {
		this.accountService = accountService;
	}

	public void setEventtService(EventService eventtService) {
		this.eventtService = eventtService;
	}

	public void setUserNotifications(UserNotifications userNotifications) {
		this.userNotifications = userNotifications;
	}

	@Override
	public List<BetHistoryDescriptor> getPendingUserBetsDescription(String userId) {
		return getBetStore().getPendingUserBetsDescription(userId);
	}

}
